<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>虚拟列表-固定高度</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      ul,
      ol {
        list-style: none;
      }

      html,
      body {
        height: 100%;
      }

      body {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        gap: 20px;
      }

      .container {
        height: 500px;
        border: 1px solid;
        overflow-y: scroll;
      }

      .list {
        width: 500px;
        box-sizing: border-box;
      }

      .item {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 57px;
        border-bottom: 1px solid gray;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <button class="btn">渲染数据</button>
    <div class="container">
      <ul class="list">
        <li class="item">1</li>
      </ul>
    </div>
    <script>
      const $container = document.querySelector('.container')
      const $list = document.querySelector('.list')
      const $btn = document.querySelector('.btn')
      const datas = new Array(10000).fill(0).map((v, i) => `<li class="item">${i}#${Math.random().toString(36).slice(2)}</li>`)
      let startIndex = 0;
      let pageSize = 20; // 一页多少条
      const fixHeight = 57; // 每一项的固定高度
      const totalHeight = fixHeight * datas.length; // 总的高度

      function render(){
        const endIndex = startIndex + pageSize
        // 前面的 startIndex 项被移除掉了，但是距离还是存在，所以需要通过paddingTop去占位
        // 就是移除了多少元素就占多少高度，原因就是 totalHeight 始终不变，所以移除 dom 元素，一定要补充占位
        $list.style.paddingTop = `${startIndex * fixHeight}px`;
        $list.innerHTML = datas.slice(startIndex, endIndex).join("")
      }

      // 点击按钮，类似与模拟请求
      $btn.addEventListener('click', function(e) {
        // 产生正确的滚动条
        $list.style.height = `${totalHeight}px`;
        render()
      })

      $container.addEventListener('scroll', function(e) {
        const scrollTop = this.scrollTop // 滚多少距离
        // const count = Math.floor(scrollTop / fixHeight)  // 滚动条滚动了多个 item
        // startIndex = count
        startIndex = Math.floor(scrollTop / fixHeight)
        render()
      })
    </script>
  </body>
</html>
